/*
 * main.java
 * 
 * last update: 16.01.2010 by Stefan Saru
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */
package engine;
import middle.*;

import java.io.*;
import java.util.*;
/**
 * This class contains the entry points for the simulation engine:
 *   main, when running as a stand-alone application and
 *   runParser, whenn called by the IDE
 */

public final class main {
	/**
	 * the parser
	 */
	static VeriParser parser;   // pt. SwitchTo

	volatile public static DummyVCDReader historyManager = new DummyVCDReader();
	static Object historyManagerLock = new Object();

	/**
	 * Keeps track of the simulation time.
	 */
	public static Cronometer cronos;

	/**
	 * True if we only preprocess files.
	 */
	public static boolean preprocessOnly;

	/**
	 * True if we only dump exported modules.
	 */
	public static boolean export;

	static boolean verbose = false;

	static TopModule topModule;
	static ScopeNode root = new DummyWatchNode();

	/**
	 * Second entry point for IDE interfacing.
	 */
	public static final void runParser(String args[], ScopeNode root,
			TimeUnitChangeListener tucl,
			IOManager io)
	{
		xConsole.debug("parser started");
		main.root = root;
		xConsole.setIOManager(io);

		//switch to IDE listener & historyManager
		historyManager = new RuntimeVCDReader(tucl);
		main(args);
	}

	/**
	 * Returns the historyManager, blocking the caller until it
	 * is created.
	 */
	public static final VCDReader getVCDReader(){
		synchronized (historyManagerLock) {
			try { 
				historyManagerLock.wait();
			} catch (InterruptedException intex) {}
			historyManagerLock.notify();
		}
		return historyManager;
	}


	/**
	 * this one will search for the "top" modules 
	 * and instantiate them
	 */
	public static final void instantiateTheWholeStuff()throws ParseException
	{
		//this @top description contains instances of all the "top" modules
		int topCount = 0;
		ModuleDescription topDescription  = new ModuleDescription("none", 0,
				VeriParser.topName);
		for (Enumeration e = VeriParser.moduleDescriptions.keys();
		e.hasMoreElements();) {
			String name = (String)e.nextElement();
			if(((ModuleFactory)VeriParser.moduleDescriptions.get(name)).isTop()){
				//if it is top , create an implicit instance 
				//description with the same name as the desc.
				//into the topmost module
				topCount++;
				xConsole.debug("found top module: " + name);
				topDescription.addSubModule(name, 0, name, new Vector(), new
						Hashtable(), new Vector(),
						Strength.defaultStrength, null);
			}
		}
		topModule = new TopModule(topDescription, root);
		if (topCount < 1) throw new ParseException("no top modules");
		xConsole.debug(topCount + " top module" + (topCount > 1 ? "s" : "") + " found");
	}

	/**
	 * this should nullify as many references as it can, 
	 * in order to help gc
	 */
	public static void performCleanup() {
		VeriParser.performCleanup();
		historyManager = null;
		topModule = null;
		parser = null;
		synchronized (historyManagerLock) {
			historyManagerLock.notifyAll();
		}
	}

	/**
	 * Stand-alone entry point.
	 */
	public static void main(String args[]){   

		cronos = new Cronometer();
		cronos.start();
		VeriParser.init();
		ModuleLoader.setLibDirs();

		int i=0;
		if(args.length !=0){
			//default switches:
			xConsole.__debug__ = false;
			verbose = false;
			xConsole.setRunMode(xConsole.COM_GO);
			export = false;

			if(args[0].startsWith("-")){
				i++;
				//switches parsing:
				if(args[0].indexOf("v") != -1){
					xConsole.cout("vIDE Verilog(R) simulator version 0.2Beta\n" +
					"See the file \"Licence\" for info about legal stuff\n");
				}
				if(args[0].indexOf("s") != -1){
					//step-by step mode:
					xConsole.setRunMode(xConsole.COM_STEP);
				}
				if(args[0].indexOf("d") != -1){
					//verbose mode
					xConsole.__debug__ = true;
				}
				if(args[0].indexOf("p") != -1){
					//debug parser
					verbose = true;
				}
				if(args[0].indexOf("t0") != -1){
					//trace enable/disable
					xConsole.enableTracing(false);
				}
				if(args[0].indexOf("t1") != -1){
					//trace enable/disable
					xConsole.enableTracing(true);
				}
				if(args[0].indexOf("w1") != -1){
					//warnings enable/disable
					xConsole.enableWarnings(true);
				}
				if(args[0].indexOf("w0") != -1){
					//warnings enable/disable
					xConsole.enableWarnings(false);
				}
				if(args[0].indexOf("l") != -1){
					//dump objects
					export = true;
				}
				if(args[0].indexOf("h") != -1){
					//display help
					xConsole.cout("Usage : java engine.VeriParser [-v|s|d|p|h|t0|t1|l] [FILE]...\n" + 
							" v\t\tprints version & copyright\n" +
							" s\t\tenters step-by-step mode\n" +
							" d,p\t\tprints lots of ugly debug info's\n" +
							" t1/t0\t\tenables/disables tracing\n" +
							" w1/w0\t\tenables/disables warnings\n" +
							" l\t\tcreate object files with exported modules\n" +
							" E\t\tpreprocess only; the output is sent to stdout" +
					" h\t\tprints this help message\n");
					return;
				}
			}
		}

		if(i < args.length){   //some filenames are given...
			for(;i<args.length;i++){
				try{
					xConsole.trace("parsing file \"" + args[i] + "\"");
					VeriParser.fileName = args[i];
					parser = new VeriParser(new FileReader(args[i]));
					if(verbose) {
						parser.enable_tracing();
						xConsole.tokenManagerTrace = true;
					} else {
						parser.disable_tracing();
						xConsole.tokenManagerTrace = false;
					}
					try{
						ParseException.currentFile = args[i];
						parser.start(args[i]);
					} catch ( ParseException ex){
						xConsole.dumpStack(ex);
						performCleanup();
						xConsole.cout(ex.getMessage() + '\n');
						return;
					} 
				} catch ( FileNotFoundException ex ){
					performCleanup();
					xConsole.cout("could not find file \"" + args[i] + "\"\n");
					return;
				} catch ( TokenMgrError te) {
					xConsole.dumpStack(te);
					performCleanup();
					xConsole.cout(te.getMessage() + '\n');
					return;     
				}
			}
		}else{    //no file given at the command line(pipe or something ?)
			VeriParser.fileName = "stdin";
			try {
				parser = new VeriParser(System.in);
				if(verbose) {
					parser.enable_tracing();
					xConsole.tokenManagerTrace = true;
				} else {
					parser.disable_tracing();
					xConsole.tokenManagerTrace = false;
				}
				xConsole.cout("Reading from standard input:\n");
				try {
					parser.start("in");
				} catch(ParseException ex) {
					xConsole.dumpStack(ex);
					performCleanup();

					xConsole.cout(ex.getMessage() + '\n');
					return;
				}
			} catch ( TokenMgrError te) {
				xConsole.dumpStack(te);
				performCleanup();
				xConsole.debug("parser error:" + te.getMessage());
				return;     
			}
		}
		try {
			try {
				xConsole.debug("checkin' up...");
				VeriParser.performCheckup();
				xConsole.debug("done");
			} catch (ParseException ex) {
				xConsole.dumpStack(ex);
				xConsole.cout(ex.getMessage() + '\n');
				performCleanup();
				return;
			}
			if (export) {
				xConsole.debug("writing objects...");
				for (Enumeration e = VeriParser.exportedModules.elements() ;
				e.hasMoreElements() ;) {
					String s = (String) e.nextElement();
					ModuleDescription md =
						(ModuleDescription) VeriParser.moduleDescriptions.get(s);
					if(md == null){
						xConsole.cout("error: exported module \"" + s + "\" not found");
					} else {
						xConsole.cout("writing \"" + s + ".vo\"\n");
						ModuleLoader.writeModule(md);
					}
				}
				xConsole.debug("done");
			} else
				try {
					xConsole.debug("instantiating the stuff...");
					instantiateTheWholeStuff();
					xConsole.debug("done");
					synchronized(historyManagerLock) {
						historyManagerLock.notifyAll();
					}
					xConsole.debug("starting simulation");
					Time.addAfterFinish((DummyVCDReader)historyManager);
					Time.startSimulation();
					xConsole.debug("running simulation");
					Time.runSimulation();
					xConsole.debug("simulation ended");
				} catch (ParseException ex) {
					xConsole.dumpStack(ex);
					xConsole.cout(ex.getMessage() + '\n');
					return;
				}
		} catch (Throwable err) {
			//if something went wrong, stop all the threads and make clean
			xConsole.debug("brrrr... ");
			xConsole.dumpStack(err);
			Time.stopSimulation();
			throw new Error("simulation error: " + err);
		} finally {
			performCleanup();
		}
		cronos.stop();
		xConsole.cout("Simulation time: " + cronos + '\n');
	}
}




